// #ifndef __tenacitas_distributed__extension__h__
// #define __tenacitas_distributed__extension__h__


// // =============================================================================
// /**
//    @file 
//    Implements @p extension and @p extensions
// */


// // =============================================================================
// //                                 C++ Headers
// #include <list>
// #include <thread>
// #include <mutex>
// #include <memory>
// #include <sstream>
// #include <cstdint>

// // =============================================================================
// //                                 3rds Headers



// // =============================================================================
// //                                 Our Headers

// #include "call_recorder.h"

// // =============================================================================
// //                                 Namespaces
// using namespace std;


// // =============================================================================
// //                                 Macro Contants

// /**
//  */


// // =============================================================================
// //                                 Macro Commands

// /**
//  */


// /**
//    namespace of the organization
// */
// namespace tenacitas {
//     /**
//        namespace for the project
//     */
//     namespace distributed {

//         // =====================================================================
//         //                             Typedefs

//         /**
//          */


//         // =====================================================================
//         //                             Pre-Declarations
//         template<typename t_recorder, typename t_attendant, typename t_phone_company>
//         class extension;

//         template<typename t_recorder, typename t_attendant, typename t_phone_company>
//         class extensions;
        

//         // =====================================================================
//         //                             Attributes

//         /**
//          */


//         // =====================================================================
//         //                             Functions

//         /**
//          */


//         // =====================================================================
//         //                             Classes

//         /** 
//             Collection of @p extension objects
//             @nosubgrouping 
//         */
//         template<typename t_recorder, typename t_attendant, typename t_phone_company>
//         class extensions {

//         public:

//             // -----------------------------------------------------------------
//             //    extensions - Public Internal Types

//             typedef std::shared_ptr<extensions> ptr;

//             typedef t_recorder recorder_type;
            
//             typedef typename recorder_type::ptr recorder_ptr;

//             typedef t_attendant attendant_type;

//             typedef typename attendant_type::ptr attendant_ptr;

//             typedef t_phone_company phone_company_type;

//             typedef typename phone_company_type::ptr phone_company_ptr;

//             typedef extension<recorder_type,
//                               attendant_type,
//                               phone_company_type> extension_type;  
            
//             /** @p extension pointer */
//             typedef typename extension_type::ptr extension_ptr;

//             /** the list of @p extension pointer */
//             typedef std::list<extension_ptr> extension_list;

//             typedef typename extension_list::iterator position;

//             // -----------------------------------------------------------------
//             //    extensions - Public Constructors
            
//             /** Constructor */
//             template <typename t_attendants_ptr>
//             extensions( std::uint16_t p_num_extensions, recorder_ptr p_recorder,
//                         t_attendants_ptr p_attendants,
//                         phone_company_ptr p_phone_company ) :
//                 m_recorder( p_recorder ),
//                 m_free( ),
//                 m_busy( ),
//                 m_mutex( ) {

//                 for ( std::uint16_t l_i = 0; l_i < p_num_extensions; ++l_i ) {
//                     m_free.push_back( 
//                         extension_ptr(
//                             new extension_type (
//                                 p_attendants->find( ),
//                                 p_phone_company,
//                                 p_recorder ) ) );
//                 }
//             }

//             /**
//                Destructor
//             */
//             ~extensions ( ) {}
            

//             // -----------------------------------------------------------------
//             //    extensions - Public Accessors

//             /** Adds an extension to the set of extensions

//                 @param [in] p_extension is the @p extension pointer to be
//                 inserted into the list
//             */
//             position add( extension_ptr p_extension ) {
//                 rec_in( m_recorder );

//                 std::lock_guard<std::mutex> l_lock(m_mutex);
                
//                 m_busy.push_back( p_extension );

//                 position l_pos = m_busy.end( );
                
//                 --l_pos;

//                 rec_out( m_recorder );

//                 return l_pos;
//             }

            
//             /** tries to find an available extension, where an attendant is free
//                 to answer a call */
//             bool find_available( position & p_pos ) {
//                 rec_in( m_recorder );

//                 std::lock_guard<std::mutex> l_lock(m_mutex);
                
//                 p_pos = m_free.end( );

//                 if ( !m_free.empty( ) ) {
//                     rec_debug( m_recorder,
//                                "there is at least one free extension" );
                    
//                     // there is at least one free extension
//                     position l_pos_free = m_free.begin( );

//                     // that will become busy
//                     m_busy.push_back( *l_pos_free );
//                     p_pos = m_busy.end( );
//                     --p_pos;

//                     // removing the extension from the free extensions list
//                     m_free.erase( l_pos_free );
//                 }

//                 rec_out( m_recorder );
//                 return ( p_pos != m_free.end( ) );
//             }

//             /** informs that a extension that was busy is now free to accept new
//                 calls */
//             void set_available( position p_pos_busy ) {
//                 rec_in( m_recorder );
                
//                 std::lock_guard<std::mutex> l_lock(m_mutex);

//                 extension_ptr l_extension = *p_pos_busy;

//                 // add the free extension to the free extensions list
//                 m_free.push_back( l_extension );

//                 // remove it from the busy extensions list
//                 m_busy.erase( p_pos_busy );

//                 rec_out( m_recorder );
//             }
            
            
//             // -----------------------------------------------------------------
//             //    extensions - Public Processors

//             /** Stops all the extensions */
//             void stop( ) {
//                 rec_in( m_recorder );
                
//                 hang_up( );
                
//                 rec_out( m_recorder );
//             }

//             /** Waits for all the on-going calls to finish */
//             void wait( ) {
//                 rec_in( m_recorder );
                
//                 hang_up( );
                
//                 rec_out( m_recorder );
//             }
            
//         private:

//             // -----------------------------------------------------------------
//             //    extensions - Private Internal Types

//             /** */
//             void hang_up( ) {
//                 for ( position l_pos = m_busy.begin( );
//                       l_pos != m_busy.end( );
//                       ++l_pos ) { 
//                     if ( ( *l_pos ) ) {
//                         if ( ( *l_pos )->busy( ) ) {
//                             std::lock_guard<std::mutex> l_lock(m_mutex);
//                             ( *l_pos )->stop( );
//                         }
//                     }
//                 }
//             }



//             // -----------------------------------------------------------------
//             //    extensions - Private Attributes

//             recorder_ptr m_recorder;

//             /** list of free extensions */
//             extension_list m_free;

//             /** list of busy extensions */
//             extension_list m_busy;

//             /** mutex for protecting shared memory */
//             std::mutex m_mutex;
//         };


        
//         /** 

//             @nosubgrouping 
//         */
//         template<typename t_recorder,
//                  typename t_attendant,
//                  typename t_phone_company> 
//         class extension {

//         public:

//             // -----------------------------------------------------------------
//             //    extension - Public Internal Types

//             typedef std::shared_ptr<extension> ptr;

//             typedef t_recorder recorder_type;
            
//             typedef typename recorder_type::ptr recorder_ptr;

//             typedef t_attendant attendant_type;

//             typedef typename attendant_type::ptr attendant_ptr;

//             typedef t_phone_company phone_company_type;

//             typedef typename phone_company_type::ptr phone_company_ptr;
            

//             // -----------------------------------------------------------------
//             //    extension - Public Constructors

//             /** Constructor */
//             extension( attendant_ptr p_attendant,
//                        phone_company_ptr p_phone_company,
//                        recorder_ptr p_recorder ) :
//                 m_attendant( p_attendant ),
//                 m_phone_company( p_phone_company ),
//                 m_recorder( p_recorder ),
//                 m_thread( ) {}
            

//             /** Destructor */
//             ~extension( ) {
//                 rec_in( m_recorder );

//                 if ( m_thread.get_id( ) != std::thread::id( ) ) {
//                     m_thread.join( );
//                 }

//                 rec_out( m_recorder );
//             }

//             // -----------------------------------------------------------------
//             //    extension - Public Processors

            
//             // -----------------------------------------------------------------
//             //    extension - Public Processors

            
//             /** Initiates the call */
//             template <typename t_call_ptr,
//                       typename t_extensions_ptr,
//                       typename t_extensions_position>
//             void accept( t_call_ptr p_call,
//                          t_extensions_ptr p_extensions,
//                          t_extensions_position p_position ) {
//                 rec_in( m_recorder );

//                 if ( m_thread.get_id( ) != std::thread::id( ) ) {
                    
//                     rec_debug( m_recorder, "waiting for the thread to finish");
                
//                     m_thread.join( );

//                     rec_debug( m_recorder, "thread finished" );
//                 }
//                 else {
//                     rec_debug( m_recorder, "thread not ever created" );
//                 }

//                 m_thread =
//                     std::thread( &extension::talk<t_call_ptr,
//                                                   t_extensions_ptr,
//                                                   t_extensions_position>,
//                                  this, p_call, p_extensions, p_position ); 


//                 rec_out( m_recorder );
//             }

//             /** Waits for the on-going call to finish */
//             void wait( ) {
//                 if ( m_thread.get_id( ) != std::thread::id( ) ) {
//                     m_thread.join( );
//                 }
                
//             }
            
//             /** Stops the on-going call */
//             void stop( ) {
//                 if ( m_thread.get_id( ) != std::thread::id( ) ) {
//                     m_thread.join( );
//                 }
//             }

//             /** */
//             bool busy( ) {
//                 return ( m_thread.get_id( ) != std::thread::id( ) );
//             }
            
            
//             // -----------------------------------------------------------------
//             //    extension - Public Attributes
            
//         private:

//             // -----------------------------------------------------------------
//             //    extension - Private Internal Types
            
//             // -----------------------------------------------------------------
//             //    extension - Private Constructors


//             extension( );

//             // -----------------------------------------------------------------
//             //    extension - Private Processors
            
//             template <typename t_call_ptr,
//                       typename t_extensions_ptr,
//                       typename t_extensions_position>
//             void talk( t_call_ptr p_call,
//                        t_extensions_ptr p_extensions,
//                        t_extensions_position p_position ) {

//                 rec_in( m_recorder );

//                 std::lock_guard<std::mutex> l_lock( m_mutex );
                
//                 rec_debug( m_recorder, "talking" );

//                 p_call->being_answered( );
        
//                 m_attendant->answer( p_call, m_phone_company );

//                 p_call->over( );

//                 rec_debug( m_recorder, "end of talk" );

//                 p_extensions->set_available( p_position );

//                 rec_out( m_recorder );
//             }

//             // -----------------------------------------------------------------
//             //    extension - Private Operators

//             extension & operator = ( const extension & );

//             // -----------------------------------------------------------------
//             //    extension - Private Attributes

//             attendant_ptr m_attendant;

//             phone_company_ptr m_phone_company;

//             recorder_ptr m_recorder;

//             std::thread m_thread;

//             bool m_over;

//             std::mutex m_mutex;

//         };

//     }
// }

// // =============================================================================
// //                     I M P L E M E N T A T I O N
// // =============================================================================

// using namespace tenacitas::distributed;


// // #############################################################################
// // extensions



// // #############################################################################
// // extension

// #endif
